package test

import (
	"crypto/md5"
	 "crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"errors"
	"git.900sui.cn/kc/kcgin"
	"os"
	"sort"
)

//新大陆支付业务逻辑

type xindalupay struct {
	privateKey       string //私钥证书
	publicKey        string //公钥证书
	driveNo          string //码牌编号 自定义
	agetId           string  //机构号
	custId           string //商户号
	wxMchid          string //微信商户号
	wxAppid          string //微信appid
	wxUrl            string //微信支付url
	wxNotifyUrl      string //回调地址-微信
	notifyUrl        string //回调地址-云收款
}

func NewXindalupay(privateKey string, publicKey string) *xindalupay {
	return &xindalupay{privateKey: privateKey, publicKey: publicKey}
}


const (
	//杭州
	CHANNELAREA_xindalu = 328 //支付地点
	//#支付渠道
	//平安云收款
	CHANNELPAY_xindalu = "XINDALUPAY" //支付机构

	DEFAULT_DRIVENO = "xindalupay" //默认的码牌编号
)
var Xindalupay *xindalupay

//生成自定义的码牌编号
func (x *xindalupay) getDriveNo()  {
	if x.driveNo == "" {
		x.driveNo = DEFAULT_DRIVENO
	}
}

//初始化
func (x *xindalupay) Init(cid int) (err error)  {
	//杭州地区参数化
	if cid == CHANNELAREA_xindalu {
		Xindalupay = &xindalupay{
			privateKey:       kcgin.AppConfig.String("xindalu.shPrivateKey"),
			publicKey:        kcgin.AppConfig.String("xindalu.shPublicKey"),
			agetId:           kcgin.AppConfig.String("xindalu.shAgetId"),
			custId:           kcgin.AppConfig.String("xindalu.shCustId"),
			driveNo:          kcgin.AppConfig.String("xindalu.shDriveNo"),
			wxMchid:          kcgin.AppConfig.String("xindalu.shWxMchid"),
			wxAppid:          kcgin.AppConfig.String("xindalu.shWxAppid"),
			wxUrl:            kcgin.AppConfig.String("xindalu.shWXurl"),
			wxNotifyUrl:      kcgin.AppConfig.String("xindalu.shWXNotifyUrl"),
		}
	}else {
		err = errors.New("当前城市未开通新大陆支付通道配置")
		return
	}
	return
}


//Sha256加密
func Sha256(src string) string {
	m := sha256.New()
	m.Write([]byte(src))
	res := hex.EncodeToString(m.Sum(nil))
	return res
}

//Sha1加密 普通shal加密
func Sha1(src string) string {
	m := sha1.New()
	m.Write([]byte(src))
	res := hex.EncodeToString(m.Sum(nil))
	return res
}

//md5加密
func Md5(src string) string {
	m := md5.New()
	m.Write([]byte(src))
	res := hex.EncodeToString(m.Sum(nil))
	return res
}

func (x *xindalupay) getSHA256(signMap map[string]interface{}) (shal256Str string,err error)  {
	keys := []string{}
	for k, _ := range signMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	strs := ""
	for _, v := range keys {
		if signMap[v] == "" {
			continue
		}
		strs += v + "=" + signMap[v].(string) + "&"
	}
	strs = strs[0:len(strs)-1] //去掉最后一个 &
	shal256Str = Sha256(strs) //对字符串进行sha256加密
	return shal256Str,nil
}

//RSA加密
func (x *xindalupay)RSA_Encrypt(plainText []byte)([]byte,error){
	//打开文件
	file,err:=os.Open(x.publicKey)
	if err!=nil{
		panic(err)
	}
	defer file.Close()
	//读取文件的内容
	info, _ := file.Stat()
	buf:=make([]byte,info.Size())
	file.Read(buf)
	//pem解码
	block, _ := pem.Decode(buf)
	//x509解码

	publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err!=nil{
		return nil,err
	}
	//类型断言
	publicKey:=publicKeyInterface.(*rsa.PublicKey)
	//对明文进行加密
	cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
	if err!=nil{
		return nil,err
	}
	//返回密文
	return cipherText,nil
}


//RSA解密
//直接读取的方式
//cipherText []byte 加密的[]byte
//私钥的位置信息
func  (x *xindalupay)RSA_Decrypt(cipherText []byte) ([]byte,error){
	//打开文件
	file,err:=os.Open(x.privateKey)
	if err!=nil{
		return nil, err
	}
	defer file.Close()
	//获取文件内容
	info, _ := file.Stat()
	buf:=make([]byte,info.Size())
	file.Read(buf)
	//pem解码
	block, _ := pem.Decode(buf)
	//X509解码
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err!=nil{
		panic(err)
	}
	//对密文进行解密
	plainText,_:=rsa.DecryptPKCS1v15(rand.Reader,privateKey,cipherText)
	//返回明文
	return plainText,nil
}

//@param publicKey key
//@param plainText 明文
//RSA加密
func (x *xindalupay) encrypt(plainText string) (string,error) {
	         //调用内部加密算法
	   sign_byte,err :=x.RSA_Encrypt([]byte(plainText))
	   return string(sign_byte),err
}
//@param 需要解密的字符串
//@return string,error "",err
func (x *xindalupay) dncrypt(plainText string) (string,error)  {
	decode_byte,err := x.RSA_Decrypt([]byte(plainText)) //rsa_decrpt 解密
	return string(decode_byte),err
}
//后台类签名
func (x *xindalupay) Sign(signMap map[string]interface{}) (sign string, err error) {
	shal256WithStr,_:= x.getSHA256(signMap)
	sign,err = x.encrypt(shal256WithStr)
	return
}
